//==========================================================================
// Copyright (c) 2000-2006,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <elasys_server.h>
#include "wincetypes.h"
#include <buf_io.h>
#include <gdivga.h>
#include <sdl.h>
#include <SDL_syswm.h>
#include <framebuffer.h>

//#include <cursor_data.h> // include the cursor data
#include "SDL_thread.h"

// Special message for WIN32 platform in SDL

#define CAPTION_MAXLENGTH               100
#define DEFAULT_CAPTION  L"Elastos Emulator(Default Mobile)"
#define DEFAULT_BASEPLANECOLORFORMAT L"RGB565"
#define DEFAULT_LCDWIDTH  176 //240
#define DEFAULT_LCDHEIGHT 220 //320
#define DEFAULT_MOBILEWIDTH  176 //240
#define DEFAULT_MOBILEHEIGHT 220 //320
#define DEFAULT_LCDPOSX 0
#define DEFAULT_LCDPOSY 0

#define SDLPIXELBITS 16  //All color format trun to RGB565

#define DRAWSURFACETIMER 40

//for power management
BufferCopy  g_BufferCopy;
UInt32 g_VideoPowerMode;

// SDL Control
_ELASTOS Boolean g_bSDLThreadOK;
SDL_Surface *g_pSurface;
SDL_Cursor *g_pCursor;

VideoContext g_videoCtx;


EXTERN_C wchar_t * CDECL _GetEnvironment(const wchar_t *envstring);
//EXTERN_C int TouchScreen(SDL_Event *pEvent, TouchType type);
//EXTERN_C int KeyPress(SDL_Event *pEvent, KeyType type);

#define PTINOVERLAY  (1 << 16)

// 18bits(occupy 32bits) to 24 bits(occupy 32bits)
#define ColorRGBT666ToRGB888(color) (DWORD)((((DWORD)color & 0x3F000) << 6) | \
                                (((DWORD)color & 0x000FC0) << 4) | \
                                (((DWORD)color & 0x00003F) << 2))

#define ColorRGBT666ToRGB565(color) (WORD)((((DWORD)color & 0x3E000) >> 2) | \
                                (((DWORD)color & 0x000FC0) >> 1) | \
                                (((DWORD)color & 0x00003F) >> 1))

#define ColorRGBT555ToRGB565(color) (WORD)((((WORD)color & 0xFFE0) << 1) | \
                                ((WORD)color & 0x001F))


Boolean GetTheoverlapArea()
{
    int Overlay1_Width = g_videoCtx.overlay1.Width;
    int Overlay1_Height = g_videoCtx.overlay1.Height;
    int Overlay1_PosX = g_videoCtx.overlay1.PosX;
    int Overlay1_PosY = g_videoCtx.overlay1.PosY;

    int Overlay2_Width = g_videoCtx.overlay2.Width;
    int Overlay2_Height = g_videoCtx.overlay2.Height;
    int Overlay2_PosX = g_videoCtx.overlay2.PosX;
    int Overlay2_PosY = g_videoCtx.overlay2.PosY;

    //If Overlap there is FALSE
    if((Overlay2_PosY + Overlay2_Height) < Overlay1_PosY ||
       (Overlay1_PosY + Overlay1_Height) < Overlay2_PosY ||
       (Overlay2_PosX + Overlay2_Width) < Overlay1_PosX ||
       (Overlay1_PosX + Overlay1_Width) < Overlay2_PosX) {
        return FALSE;
    }

    //There is the overlap area
    g_videoCtx.overlapArea.PosX =
        (Overlay1_PosX >= Overlay2_PosX) ? Overlay1_PosX : Overlay2_PosX;

    g_videoCtx.overlapArea.PosY =
        (Overlay1_PosY >= Overlay2_PosY) ? Overlay1_PosY : Overlay2_PosY;

    g_videoCtx.overlapArea.Width =
        (Overlay1_PosX + Overlay1_Width) <= (Overlay2_PosX + Overlay2_Width) ?
        (Overlay1_PosX + Overlay1_Width - g_videoCtx.overlapArea.PosX) :
        (Overlay2_PosX + Overlay2_Width - g_videoCtx.overlapArea.PosX);

    g_videoCtx.overlapArea.Height =
        (Overlay1_PosY + Overlay1_Height) <= (Overlay2_PosY + Overlay2_Height) ?
        (Overlay1_PosY + Overlay1_Height - g_videoCtx.overlapArea.PosY) :
        (Overlay2_PosY + Overlay2_Height - g_videoCtx.overlapArea.PosY);

    return TRUE;
}

static void BaseplaneBufferCopy_RGB565()
{
    WORD * pSrcBuffer = (WORD *)g_videoCtx.pBasePlaneFb;
    WORD * pDesLine = (WORD *)g_pSurface->pixels;

    for (int i = 0; i < g_videoCtx.nLCDHeight; i++) {
        memcpy(
            // Dest
            (Byte *)(pDesLine + ((g_videoCtx.nLCDPosY + i) *
            g_videoCtx.nMobileWidth + g_videoCtx.nLCDPosX)),
            // Source
            (Byte *)(pSrcBuffer +
            i * g_videoCtx.nLCDWidth),
            // Bytes
            g_videoCtx.nLCDWidth * 2);
    }
}

static void BaseplaneBufferCopy_RGBT555()
{
    WORD * pSrcBuffer = (WORD *)g_videoCtx.pBasePlaneFb;
    WORD * pDesBuffer = (WORD *)g_pSurface->pixels;
    Byte * pTransArray = g_videoCtx.pTransArray;

    memset(g_videoCtx.pTransArray, 0, g_videoCtx.nTransArraySize);

    pDesBuffer = pDesBuffer +
        g_videoCtx.nLCDPosX +
        g_videoCtx.nLCDPosY * g_videoCtx.nMobileWidth;
    for (int jSrc = 0; jSrc < g_videoCtx.nLCDHeight; jSrc++) {
        for (int iSrc = 0; iSrc < g_videoCtx.nLCDWidth; iSrc++) {
            *pDesBuffer = ColorRGBT555ToRGB565(*pSrcBuffer);
            *pTransArray = *pSrcBuffer >> 15;
            pSrcBuffer++;
            pDesBuffer++;
            pTransArray++;
        }
        pDesBuffer += (g_videoCtx.nMobileWidth - g_videoCtx.nLCDWidth);
    }
}

static void BaseplaneBufferCopy_RGBT666()
{
    DWORD * pSrcBuffer = (DWORD *)g_videoCtx.pBasePlaneFb;
    WORD * pDesBuffer = (WORD *)g_pSurface->pixels;
    Byte * pTransArray = g_videoCtx.pTransArray;

    memset(g_videoCtx.pTransArray, 0, g_videoCtx.nTransArraySize);

    pDesBuffer = pDesBuffer +
        g_videoCtx.nLCDPosX +
        g_videoCtx.nLCDPosY * g_videoCtx.nMobileWidth;
    for (int jSrc = 0; jSrc < g_videoCtx.nLCDHeight; jSrc++) {
        for (int iSrc = 0; iSrc < g_videoCtx.nLCDWidth; iSrc++) {
            *pDesBuffer = ColorRGBT666ToRGB565(*pSrcBuffer);
            *pTransArray = (Byte)(*pSrcBuffer >> 18);
            pSrcBuffer++;
            pDesBuffer++;
            pTransArray++;
        }
        pDesBuffer += (g_videoCtx.nMobileWidth - g_videoCtx.nLCDWidth);
    }
}

static void Underlay_Overlay2BufferCopy_YCbCr422()
{
    WORD *pDesBuffer;
    Byte * pTransArray;

    Byte *pY, *pCb, *pCr;
    int RGB_R, RGB_G, RGB_B;
    int YCbCr_Y, YCbCr_Cb, YCbCr_Cr;

    WORD SrcPixelRed, SrcPixelGreen, SrcPixelBlue;
    WORD BlendPixelRed, BlendPixelGreen, BlendPixelBlue;

    pTransArray = g_videoCtx.pTransArray + g_videoCtx.overlay2.PosX +
                    g_videoCtx.overlay2.PosY * g_videoCtx.nLCDWidth;

    pDesBuffer = (WORD *)g_pSurface->pixels +
                    (g_videoCtx.nLCDPosY + g_videoCtx.overlay2.PosY) *
                    g_videoCtx.nMobileWidth + g_videoCtx.nLCDPosX +
                    g_videoCtx.overlay2.PosX;

    pY = (Byte *)g_videoCtx.overlay2.pChannelFb[0];
    pCb = (Byte *)g_videoCtx.overlay2.pChannelFb[1];
    pCr = (Byte *)g_videoCtx.overlay2.pChannelFb[2];

    for (int j = 0; j < g_videoCtx.overlay2.Height; j++) {
        for (int i = 0; i < g_videoCtx.overlay2.Width; i++) {
            if(0 == *pTransArray) {
                pTransArray++;
                pDesBuffer++;
                continue;
            }

            //Get the overlay2 RGB
            YCbCr_Y = (int)pY[i + j * g_videoCtx.overlay2.Width];
            YCbCr_Cb = (int)pCb[(i + j * g_videoCtx.overlay2.Width) / 2];
            YCbCr_Cr = (int)pCr[(i + j * g_videoCtx.overlay2.Width) / 2];

            RGB_R = (int)(YCbCr_Y + 1.402 * (YCbCr_Cr - 128));
            RGB_G = (int)(YCbCr_Y - 0.344 * (YCbCr_Cb - 128) - 0.714 * (YCbCr_Cr - 128));
            RGB_B = (int)(YCbCr_Y + 1.773 * (YCbCr_Cb - 128));

            if (RGB_R < 0) RGB_R = 0;
            if (RGB_R > 0xFF) RGB_R = 0xFF;

            if (RGB_G < 0) RGB_G = 0;
            if (RGB_G > 0xFF) RGB_G = 0xFF;

            if (RGB_B < 0) RGB_B = 0;
            if (RGB_B > 0xFF) RGB_B = 0xFF;

            //Full Trans
            if(*pDesBuffer == 0) {
                *pDesBuffer = ((RGB_R & 0xF8) << 8) | ((RGB_G & 0xFC) << 3) | (RGB_B >> 3);
                pTransArray++;
                pDesBuffer++;
                continue;
            }

            //Blend the pixel with setted desbuffer and overlay2 RGB
            SrcPixelRed = (*pDesBuffer & 0xF800) >> 8;
            SrcPixelGreen = (*pDesBuffer & 0x07E0) >> 3;
            SrcPixelBlue = (*pDesBuffer & 0x001F) << 3;

            switch(g_videoCtx.nTransparencyKey) {
                case 0://8/8
                    BlendPixelRed = SrcPixelRed;
                    BlendPixelGreen = SrcPixelGreen;
                    BlendPixelBlue = SrcPixelBlue;
                    break;
                case 1://7/8
                    BlendPixelRed = (WORD)((SrcPixelRed * 7/8)
                        + (RGB_R >> 3));
                    BlendPixelGreen = (WORD)((SrcPixelGreen * 7/8)
                        + (RGB_G >> 3));
                    BlendPixelBlue = (WORD)((SrcPixelBlue * 7/8)
                        + (RGB_B >> 3));
                    break;
                case 2://6/8
                    BlendPixelRed = (WORD)((SrcPixelRed * 2/3)
                        + RGB_R * 1/3);
                    BlendPixelGreen = (WORD)((SrcPixelGreen * 2/3)
                        + RGB_G * 1/3);
                    BlendPixelBlue = (WORD)((SrcPixelBlue * 2/3)
                        + RGB_B * 1/3);
                    break;
                case 3://5/8
                    BlendPixelRed = (WORD)((SrcPixelRed * 5/8)
                        + RGB_R * 3/8);
                    BlendPixelGreen = (WORD)((SrcPixelGreen * 5/8)
                        + RGB_G * 3/8);
                    BlendPixelBlue = (WORD)((SrcPixelBlue * 5/8)
                        + RGB_B * 3/8);
                    break;
                case 4://4/8
                    BlendPixelRed = (WORD)((SrcPixelRed >> 1)
                        + RGB_R  - (RGB_R >> 1));
                    BlendPixelGreen = (WORD)((SrcPixelGreen >> 1)
                        + RGB_G  - (RGB_G >> 1));
                    BlendPixelBlue = (WORD)((SrcPixelBlue >> 1)
                        + RGB_B  - (RGB_B >> 1));
                    break;
                case 5://3/8
                    BlendPixelRed = (WORD)(((SrcPixelRed >> 3) * 3)
                        + (RGB_R >> 3) * 5);
                    BlendPixelGreen = (WORD)(((SrcPixelGreen >> 3) * 3)
                        + (RGB_G >> 3) * 5);
                    BlendPixelBlue = (WORD)(((SrcPixelBlue >> 3) * 3)
                        + (RGB_B >> 3) * 5);
                    break;
                case 6://2/8
                    BlendPixelRed = (WORD)((SrcPixelRed >> 2)
                        + RGB_R  - (RGB_R >> 2));
                    BlendPixelGreen = (WORD)((SrcPixelGreen >> 2)
                        + RGB_G  - (RGB_G >> 2));
                    BlendPixelBlue = (WORD)((SrcPixelBlue >> 2)
                        + RGB_B  - (RGB_B >> 2));
                    break;
                case 7://1/8
                    // Improve efficiency
                default:
                    BlendPixelRed = (WORD)((SrcPixelRed >> 3)
                        + RGB_R  - (RGB_R >> 3));
                    BlendPixelGreen = (WORD)((SrcPixelGreen >> 3)
                        + RGB_G  - (RGB_G >> 3));
                    BlendPixelBlue = (WORD)((SrcPixelBlue >> 3)
                        + RGB_B  - (RGB_B >> 3));
                    break;
            }
            *pDesBuffer = ((BlendPixelRed & 0xF8) << 8) | ((BlendPixelGreen & 0xFC) << 3) | (BlendPixelBlue >> 3);

            pTransArray++;
            pDesBuffer++;
        }
        pTransArray += (g_videoCtx.nLCDWidth - g_videoCtx.overlay2.Width);
        pDesBuffer += (g_videoCtx.nMobileWidth - g_videoCtx.overlay2.Width);
    }

}

static void Underlay_Overlay2BufferCopy_YCbCr420()
{
    WORD *pDesBuffer;
    Byte * pTransArray;

    Byte *pY, *pCb, *pCr;
    int RGB_R, RGB_G, RGB_B;
    int YCbCr_Y, YCbCr_Cb, YCbCr_Cr;

    WORD SrcPixelRed, SrcPixelGreen, SrcPixelBlue;
    WORD BlendPixelRed, BlendPixelGreen, BlendPixelBlue;

    pTransArray = g_videoCtx.pTransArray + g_videoCtx.overlay2.PosX +
                    g_videoCtx.overlay2.PosY * g_videoCtx.nLCDWidth;

    pDesBuffer = (WORD *)g_pSurface->pixels +
                    (g_videoCtx.nLCDPosY + g_videoCtx.overlay2.PosY) *
                    g_videoCtx.nMobileWidth + g_videoCtx.nLCDPosX +
                    g_videoCtx.overlay2.PosX;

    pY = (Byte *)g_videoCtx.overlay2.pChannelFb[0];
    pCb = (Byte *)g_videoCtx.overlay2.pChannelFb[1];
    pCr = (Byte *)g_videoCtx.overlay2.pChannelFb[2];

    for (int j = 0; j < g_videoCtx.overlay2.Height; j++) {
        for (int i = 0; i < g_videoCtx.overlay2.Width; i++) {
            if(0 == *pTransArray) {
                pTransArray++;
                pDesBuffer++;
                continue;
            }

            //Get the overlay2 RGB
            YCbCr_Y = (int)pY[i + j * g_videoCtx.overlay2.Width];
            YCbCr_Cb = (int)pCb[(i + (j/2) * g_videoCtx.overlay2.Width) / 2];
            YCbCr_Cr = (int)pCr[(i + (j/2) * g_videoCtx.overlay2.Width) / 2];

            RGB_R = (int)(YCbCr_Y + 1.402 * (YCbCr_Cr - 128));
            RGB_G = (int)(YCbCr_Y - 0.344 * (YCbCr_Cb - 128) - 0.714 * (YCbCr_Cr - 128));
            RGB_B = (int)(YCbCr_Y + 1.773 * (YCbCr_Cb - 128));

            if (RGB_R < 0) RGB_R = 0;
            if (RGB_R > 0xFF) RGB_R = 0xFF;

            if (RGB_G < 0) RGB_G = 0;
            if (RGB_G > 0xFF) RGB_G = 0xFF;

            if (RGB_B < 0) RGB_B = 0;
            if (RGB_B > 0xFF) RGB_B = 0xFF;

            //Full Trans
            if(*pDesBuffer == 0) {
                *pDesBuffer = ((RGB_R & 0xF8) << 8) | ((RGB_G & 0xFC) << 3) | (RGB_B >> 3);
                pTransArray++;
                pDesBuffer++;
                continue;
            }

            //Blend the pixel with setted desbuffer and overlay2 RGB
            SrcPixelRed = (*pDesBuffer & 0xF800) >> 8;
            SrcPixelGreen = (*pDesBuffer & 0x07E0) >> 3;
            SrcPixelBlue = (*pDesBuffer & 0x001F) << 3;

            switch(g_videoCtx.nTransparencyKey) {
                case 0://8/8
                    BlendPixelRed = SrcPixelRed;
                    BlendPixelGreen = SrcPixelGreen;
                    BlendPixelBlue = SrcPixelBlue;
                    break;
                case 1://7/8
                    BlendPixelRed = (WORD)((SrcPixelRed * 7/8)
                        + (RGB_R >> 3));
                    BlendPixelGreen = (WORD)((SrcPixelGreen * 7/8)
                        + (RGB_G >> 3));
                    BlendPixelBlue = (WORD)((SrcPixelBlue * 7/8)
                        + (RGB_B >> 3));
                    break;
                case 2://6/8
                    BlendPixelRed = (WORD)((SrcPixelRed * 2/3)
                        + RGB_R * 1/3);
                    BlendPixelGreen = (WORD)((SrcPixelGreen * 2/3)
                        + RGB_G * 1/3);
                    BlendPixelBlue = (WORD)((SrcPixelBlue * 2/3)
                        + RGB_B * 1/3);
                    break;
                case 3://5/8
                    BlendPixelRed = (WORD)((SrcPixelRed * 5/8)
                        + RGB_R * 3/8);
                    BlendPixelGreen = (WORD)((SrcPixelGreen * 5/8)
                        + RGB_G * 3/8);
                    BlendPixelBlue = (WORD)((SrcPixelBlue * 5/8)
                        + RGB_B * 3/8);
                    break;
                case 4://4/8
                    BlendPixelRed = (WORD)((SrcPixelRed >> 1)
                        + RGB_R  - (RGB_R >> 1));
                    BlendPixelGreen = (WORD)((SrcPixelGreen >> 1)
                        + RGB_G  - (RGB_G >> 1));
                    BlendPixelBlue = (WORD)((SrcPixelBlue >> 1)
                        + RGB_B  - (RGB_B >> 1));
                    break;
                case 5://3/8
                    BlendPixelRed = (WORD)(((SrcPixelRed >> 3) * 3)
                        + (RGB_R >> 3) * 5);
                    BlendPixelGreen = (WORD)(((SrcPixelGreen >> 3) * 3)
                        + (RGB_G >> 3) * 5);
                    BlendPixelBlue = (WORD)(((SrcPixelBlue >> 3) * 3)
                        + (RGB_B >> 3) * 5);
                    break;
                case 6://2/8
                    BlendPixelRed = (WORD)((SrcPixelRed >> 2)
                        + RGB_R  - (RGB_R >> 2));
                    BlendPixelGreen = (WORD)((SrcPixelGreen >> 2)
                        + RGB_G  - (RGB_G >> 2));
                    BlendPixelBlue = (WORD)((SrcPixelBlue >> 2)
                        + RGB_B  - (RGB_B >> 2));
                    break;
                case 7://1/8
                    // Improve efficiency
                default:
                    BlendPixelRed = (WORD)((SrcPixelRed >> 3)
                        + RGB_R  - (RGB_R >> 3));
                    BlendPixelGreen = (WORD)((SrcPixelGreen >> 3)
                        + RGB_G  - (RGB_G >> 3));
                    BlendPixelBlue = (WORD)((SrcPixelBlue >> 3)
                        + RGB_B  - (RGB_B >> 3));
                    break;
            }
            *pDesBuffer = ((BlendPixelRed & 0xF8) << 8) | ((BlendPixelGreen & 0xFC) << 3) | (BlendPixelBlue >> 3);

            pTransArray++;
            pDesBuffer++;
        }
        pTransArray += (g_videoCtx.nLCDWidth - g_videoCtx.overlay2.Width);
        pDesBuffer += (g_videoCtx.nMobileWidth - g_videoCtx.overlay2.Width);
    }

}

static void Overlay_Overlay2BufferCopy_YCbCr422()
{
    WORD *pDesBuffer;
    Byte *pY, *pCb, *pCr;
    int RGB_R, RGB_G, RGB_B;
    int YCbCr_Y, YCbCr_Cb, YCbCr_Cr;

    pDesBuffer = (WORD *)g_pSurface->pixels +
                    (g_videoCtx.nLCDPosY + g_videoCtx.overlay2.PosY) *
                    g_videoCtx.nMobileWidth + g_videoCtx.nLCDPosX +
                    g_videoCtx.overlay2.PosX;

    pY = (Byte *)g_videoCtx.overlay2.pChannelFb[0];
    pCb = (Byte *)g_videoCtx.overlay2.pChannelFb[1];
    pCr = (Byte *)g_videoCtx.overlay2.pChannelFb[2];

    for (int j = 0; j < g_videoCtx.overlay2.Height; j++) {
        for (int i = 0; i < g_videoCtx.overlay2.Width; i++) {
            YCbCr_Y = (int)pY[i + j * g_videoCtx.overlay2.Width];
            YCbCr_Cb = (int)pCb[(i + j * g_videoCtx.overlay2.Width) / 2];
            YCbCr_Cr = (int)pCr[(i + j * g_videoCtx.overlay2.Width) / 2];

            RGB_R = (int)(YCbCr_Y + 1.402 * (YCbCr_Cr - 128));
            RGB_G = (int)(YCbCr_Y - 0.344 * (YCbCr_Cb - 128) - 0.714 * (YCbCr_Cr - 128));
            RGB_B = (int)(YCbCr_Y + 1.773 * (YCbCr_Cb - 128));

            if (RGB_R < 0) RGB_R = 0;
            if (RGB_R > 0xFF) RGB_R = 0xFF;

            if (RGB_G < 0) RGB_G = 0;
            if (RGB_G > 0xFF) RGB_G = 0xFF;

            if (RGB_B < 0) RGB_B = 0;
            if (RGB_B > 0xFF) RGB_B = 0xFF;

            *pDesBuffer =
                    ((RGB_R & 0xF8) << 8) | ((RGB_G & 0xFC) << 3) | (RGB_B >> 3);
            pDesBuffer++;
        }
        pDesBuffer += (g_videoCtx.nMobileWidth - g_videoCtx.overlay2.Width);
    }
}

static void Overlay_Overlay2BufferCopy_YCbCr420()
{
    WORD *pDesBuffer;
    Byte *pY, *pCb, *pCr;
    int RGB_R, RGB_G, RGB_B;
    int YCbCr_Y, YCbCr_Cb, YCbCr_Cr;

    pDesBuffer = (WORD *)g_pSurface->pixels +
                    (g_videoCtx.nLCDPosY + g_videoCtx.overlay2.PosY) *
                    g_videoCtx.nMobileWidth + g_videoCtx.nLCDPosX +
                    g_videoCtx.overlay2.PosX;

    pY = (Byte *)g_videoCtx.overlay2.pChannelFb[0];
    pCb = (Byte *)g_videoCtx.overlay2.pChannelFb[1];
    pCr = (Byte *)g_videoCtx.overlay2.pChannelFb[2];

    for (int j = 0; j < g_videoCtx.overlay2.Height; j++) {
        for (int i = 0; i < g_videoCtx.overlay2.Width; i++) {
            YCbCr_Y = (int)pY[i + j * g_videoCtx.overlay2.Width];
            YCbCr_Cb = (int)pCb[(i + (j/2) * g_videoCtx.overlay2.Width) / 2];
            YCbCr_Cr = (int)pCr[(i + (j/2) * g_videoCtx.overlay2.Width) / 2];

            RGB_R = (int)(YCbCr_Y + 1.402 * (YCbCr_Cr - 128));
            RGB_G = (int)(YCbCr_Y - 0.344 * (YCbCr_Cb - 128) - 0.714 * (YCbCr_Cr - 128));
            RGB_B = (int)(YCbCr_Y + 1.773 * (YCbCr_Cb - 128));

            if (RGB_R < 0) RGB_R = 0;
            if (RGB_R > 0xFF) RGB_R = 0xFF;

            if (RGB_G < 0) RGB_G = 0;
            if (RGB_G > 0xFF) RGB_G = 0xFF;

            if (RGB_B < 0) RGB_B = 0;
            if (RGB_B > 0xFF) RGB_B = 0xFF;

            *pDesBuffer =
                    ((RGB_R & 0xF8) << 8) | ((RGB_G & 0xFC) << 3) | (RGB_B >> 3);
            pDesBuffer++;
        }
        pDesBuffer += (g_videoCtx.nMobileWidth - g_videoCtx.overlay2.Width);
    }
}

static void Underlay_Overlay1BufferCopy_RGBT666()
{
    WORD *pDesBuffer;
    Byte * pTransArray;
    UInt32 *pOverlay1Buffer;

    WORD RGB_R, RGB_G, RGB_B;
    WORD SrcPixelRed, SrcPixelGreen, SrcPixelBlue;
    WORD BlendPixelRed, BlendPixelGreen, BlendPixelBlue;

    pOverlay1Buffer = (UInt32 *)g_videoCtx.pOverlay1Fb;

    pTransArray = g_videoCtx.pTransArray + g_videoCtx.overlay1.PosX +
                    g_videoCtx.overlay1.PosY * g_videoCtx.nLCDWidth;

    pDesBuffer = (WORD *)g_pSurface->pixels +
                    (g_videoCtx.nLCDPosY + g_videoCtx.overlay1.PosY) *
                    g_videoCtx.nMobileWidth + g_videoCtx.nLCDPosX +
                    g_videoCtx.overlay1.PosX;

    //Blend the pixel with desbuffer which has been setted by baseplane and overlay1 RGB
    for (int j = 0; j < g_videoCtx.overlay1.Height; j++) {
        for (int i = 0; i < g_videoCtx.overlay1.Width; i++) {
            if(0 == *pTransArray) {
                pTransArray++;
                pOverlay1Buffer++;
                pDesBuffer++;
                continue;
            }

            //Overlay1 Full Trans
            if((*pOverlay1Buffer & 0x3FFFF) == 0) {
                pTransArray++;
                pOverlay1Buffer++;
                pDesBuffer++;
                continue;
            }

            //Baseplane Full Trans
            if(*pDesBuffer == 0) {
                *pDesBuffer = ColorRGBT666ToRGB565(*pOverlay1Buffer);
                pTransArray++;
                pOverlay1Buffer++;
                pDesBuffer++;
                continue;
            }


            RGB_R = (WORD)(*pOverlay1Buffer & 0x3F000) >> 10;
            RGB_G = (WORD)(*pOverlay1Buffer & 0x000FC0) >> 4;
            RGB_B = (WORD)(*pOverlay1Buffer & 0x00003F) << 2;

            SrcPixelRed = (*pDesBuffer & 0xF800) >> 8;
            SrcPixelGreen = (*pDesBuffer & 0x07E0) >> 3;
            SrcPixelBlue = (*pDesBuffer & 0x001F) << 3;

            switch(g_videoCtx.nTransparencyKey) {
                case 0://8/8
                    BlendPixelRed = SrcPixelRed;
                    BlendPixelGreen = SrcPixelGreen;
                    BlendPixelBlue = SrcPixelBlue;
                    break;
                case 1://7/8
                    BlendPixelRed = (WORD)((SrcPixelRed * 7/8)
                        + (RGB_R >> 3));
                    BlendPixelGreen = (WORD)((SrcPixelGreen * 7/8)
                        + (RGB_G >> 3));
                    BlendPixelBlue = (WORD)((SrcPixelBlue * 7/8)
                        + (RGB_B >> 3));
                    break;
                case 2://6/8
                    BlendPixelRed = (WORD)((SrcPixelRed * 2/3)
                        + RGB_R * 1/3);
                    BlendPixelGreen = (WORD)((SrcPixelGreen * 2/3)
                        + RGB_G * 1/3);
                    BlendPixelBlue = (WORD)((SrcPixelBlue * 2/3)
                        + RGB_B * 1/3);
                    break;
                case 3://5/8
                    BlendPixelRed = (WORD)((SrcPixelRed * 5/8)
                        + RGB_R * 3/8);
                    BlendPixelGreen = (WORD)((SrcPixelGreen * 5/8)
                        + RGB_G * 3/8);
                    BlendPixelBlue = (WORD)((SrcPixelBlue * 5/8)
                        + RGB_B * 3/8);
                    break;
                case 4://4/8
                    BlendPixelRed = (WORD)((SrcPixelRed >> 1)
                        + RGB_R  - (RGB_R >> 1));
                    BlendPixelGreen = (WORD)((SrcPixelGreen >> 1)
                        + RGB_G  - (RGB_G >> 1));
                    BlendPixelBlue = (WORD)((SrcPixelBlue >> 1)
                        + RGB_B  - (RGB_B >> 1));
                    break;
                case 5://3/8
                    BlendPixelRed = (WORD)(((SrcPixelRed >> 3) * 3)
                        + (RGB_R >> 3) * 5);
                    BlendPixelGreen = (WORD)(((SrcPixelGreen >> 3) * 3)
                        + (RGB_G >> 3) * 5);
                    BlendPixelBlue = (WORD)(((SrcPixelBlue >> 3) * 3)
                        + (RGB_B >> 3) * 5);
                    break;
                case 6://2/8
                    BlendPixelRed = (WORD)((SrcPixelRed >> 2)
                        + RGB_R  - (RGB_R >> 2));
                    BlendPixelGreen = (WORD)((SrcPixelGreen >> 2)
                        + RGB_G  - (RGB_G >> 2));
                    BlendPixelBlue = (WORD)((SrcPixelBlue >> 2)
                        + RGB_B  - (RGB_B >> 2));
                    break;
                case 7://1/8
                    // Improve efficiency
                default:
                    BlendPixelRed = (WORD)((SrcPixelRed >> 3)
                        + RGB_R  - (RGB_R >> 3));
                    BlendPixelGreen = (WORD)((SrcPixelGreen >> 3)
                        + RGB_G  - (RGB_G >> 3));
                    BlendPixelBlue = (WORD)((SrcPixelBlue >> 3)
                        + RGB_B  - (RGB_B >> 3));
                    break;
            }
            *pDesBuffer = ((BlendPixelRed & 0xF8) << 8) | ((BlendPixelGreen & 0xFC) << 3) | (BlendPixelBlue >> 3);

            pTransArray++;
            pOverlay1Buffer++;
            pDesBuffer++;
        }
        pTransArray += (g_videoCtx.nLCDWidth - g_videoCtx.overlay1.Width);
        pDesBuffer += (g_videoCtx.nMobileWidth - g_videoCtx.overlay1.Width);
    }
}

static void Underlay_Overlay1BufferCopy_RGB565()
{
    WORD *pDesBuffer;
    Byte * pTransArray;
    WORD *pOverlay1Buffer;

    WORD RGB_R, RGB_G, RGB_B;
    WORD SrcPixelRed, SrcPixelGreen, SrcPixelBlue;
    WORD BlendPixelRed, BlendPixelGreen, BlendPixelBlue;

    pOverlay1Buffer = (WORD *)g_videoCtx.pOverlay1Fb;

    pTransArray = g_videoCtx.pTransArray + g_videoCtx.overlay1.PosX +
                    g_videoCtx.overlay1.PosY * g_videoCtx.nLCDWidth;

    pDesBuffer = (WORD *)g_pSurface->pixels +
                    (g_videoCtx.nLCDPosY + g_videoCtx.overlay1.PosY) *
                    g_videoCtx.nMobileWidth + g_videoCtx.nLCDPosX +
                    g_videoCtx.overlay1.PosX;

    //Blend the pixel with desbuffer which has been setted by baseplane and overlay1 RGB
    for (int j = 0; j < g_videoCtx.overlay1.Height; j++) {
        for (int i = 0; i < g_videoCtx.overlay1.Width; i++) {
            if(0 == *pTransArray) {
                pTransArray++;
                pOverlay1Buffer++;
                pDesBuffer++;
                continue;
            }

            //Baseplane Full Trans
            if(*pDesBuffer == 0) {
                *pDesBuffer = *pOverlay1Buffer;
                pTransArray++;
                pOverlay1Buffer++;
                pDesBuffer++;
                continue;
            }

            RGB_R = (*pOverlay1Buffer & 0xF800) >> 8;
            RGB_G = (*pOverlay1Buffer & 0x07E0) >> 3;
            RGB_B = (*pOverlay1Buffer & 0x001F) << 3;

            SrcPixelRed = (*pDesBuffer & 0xF800) >> 8;
            SrcPixelGreen = (*pDesBuffer & 0x07E0) >> 3;
            SrcPixelBlue = (*pDesBuffer & 0x001F) << 3;

            switch(g_videoCtx.nTransparencyKey) {
                case 0://8/8
                    BlendPixelRed = SrcPixelRed;
                    BlendPixelGreen = SrcPixelGreen;
                    BlendPixelBlue = SrcPixelBlue;
                    break;
                case 1://7/8
                    BlendPixelRed = (WORD)((SrcPixelRed * 7/8)
                        + (RGB_R >> 3));
                    BlendPixelGreen = (WORD)((SrcPixelGreen * 7/8)
                        + (RGB_G >> 3));
                    BlendPixelBlue = (WORD)((SrcPixelBlue * 7/8)
                        + (RGB_B >> 3));
                    break;
                case 2://6/8
                    BlendPixelRed = (WORD)((SrcPixelRed * 2/3)
                        + RGB_R * 1/3);
                    BlendPixelGreen = (WORD)((SrcPixelGreen * 2/3)
                        + RGB_G * 1/3);
                    BlendPixelBlue = (WORD)((SrcPixelBlue * 2/3)
                        + RGB_B * 1/3);
                    break;
                case 3://5/8
                    BlendPixelRed = (WORD)((SrcPixelRed * 5/8)
                        + RGB_R * 3/8);
                    BlendPixelGreen = (WORD)((SrcPixelGreen * 5/8)
                        + RGB_G * 3/8);
                    BlendPixelBlue = (WORD)((SrcPixelBlue * 5/8)
                        + RGB_B * 3/8);
                    break;
                case 4://4/8
                    BlendPixelRed = (WORD)((SrcPixelRed >> 1)
                        + RGB_R  - (RGB_R >> 1));
                    BlendPixelGreen = (WORD)((SrcPixelGreen >> 1)
                        + RGB_G  - (RGB_G >> 1));
                    BlendPixelBlue = (WORD)((SrcPixelBlue >> 1)
                        + RGB_B  - (RGB_B >> 1));
                    break;
                case 5://3/8
                    BlendPixelRed = (WORD)(((SrcPixelRed >> 3) * 3)
                        + (RGB_R >> 3) * 5);
                    BlendPixelGreen = (WORD)(((SrcPixelGreen >> 3) * 3)
                        + (RGB_G >> 3) * 5);
                    BlendPixelBlue = (WORD)(((SrcPixelBlue >> 3) * 3)
                        + (RGB_B >> 3) * 5);
                    break;
                case 6://2/8
                    BlendPixelRed = (WORD)((SrcPixelRed >> 2)
                        + RGB_R  - (RGB_R >> 2));
                    BlendPixelGreen = (WORD)((SrcPixelGreen >> 2)
                        + RGB_G  - (RGB_G >> 2));
                    BlendPixelBlue = (WORD)((SrcPixelBlue >> 2)
                        + RGB_B  - (RGB_B >> 2));
                    break;
                case 7://1/8
                    // Improve efficiency
                default:
                    BlendPixelRed = (WORD)((SrcPixelRed >> 3)
                        + RGB_R  - (RGB_R >> 3));
                    BlendPixelGreen = (WORD)((SrcPixelGreen >> 3)
                        + RGB_G  - (RGB_G >> 3));
                    BlendPixelBlue = (WORD)((SrcPixelBlue >> 3)
                        + RGB_B  - (RGB_B >> 3));
                    break;
            }
            *pDesBuffer = ((BlendPixelRed & 0xF8) << 8) | ((BlendPixelGreen & 0xFC) << 3) | (BlendPixelBlue >> 3);

            pTransArray++;
            pOverlay1Buffer++;
            pDesBuffer++;
        }
        pTransArray += (g_videoCtx.nLCDWidth - g_videoCtx.overlay1.Width);
        pDesBuffer += (g_videoCtx.nMobileWidth - g_videoCtx.overlay1.Width);
    }
}

static void Overlay_Overlay1BufferCopy_RGBT666()
{
    WORD *pDesBuffer;
    UInt32 *pOverlay1Buffer;

    WORD RGB_R, RGB_G, RGB_B;
    WORD SrcPixelRed, SrcPixelGreen, SrcPixelBlue;
    WORD BlendPixelRed, BlendPixelGreen, BlendPixelBlue;

    pOverlay1Buffer = (UInt32 *)g_videoCtx.pOverlay1Fb;

    pDesBuffer = (WORD *)g_pSurface->pixels +
                    (g_videoCtx.nLCDPosY + g_videoCtx.overlay1.PosY) *
                    g_videoCtx.nMobileWidth + g_videoCtx.nLCDPosX +
                    g_videoCtx.overlay1.PosX;

    //Blend the pixel with desbuffer which has been setted by baseplane and overlay1 RGB
    for (int j = 0; j < g_videoCtx.overlay1.Height; j++) {
        for (int i = 0; i < g_videoCtx.overlay1.Width; i++) {
            //No trans
            if((*pOverlay1Buffer >> 18) != 1) {
                *pDesBuffer = ColorRGBT666ToRGB565(*pOverlay1Buffer);
                pOverlay1Buffer++;
                pDesBuffer++;
                continue;
            }

            //Full trans
            if((*pOverlay1Buffer & 0x3FFFF) == 0) {
                pOverlay1Buffer++;
                pDesBuffer++;
                continue;
            }
            SrcPixelRed = (WORD)(*pOverlay1Buffer & 0x3F000) >> 10;
            SrcPixelGreen = (WORD)(*pOverlay1Buffer & 0x000FC0) >> 4;
            SrcPixelBlue = (WORD)(*pOverlay1Buffer & 0x00003F) << 2;

            RGB_R = (*pDesBuffer & 0xF800) >> 8;
            RGB_G = (*pDesBuffer & 0x07E0) >> 3;
            RGB_B = (*pDesBuffer & 0x001F) << 3;

            switch(g_videoCtx.nTransparencyKey) {
                case 0://8/8
                    BlendPixelRed = SrcPixelRed;
                    BlendPixelGreen = SrcPixelGreen;
                    BlendPixelBlue = SrcPixelBlue;
                    break;
                case 1://7/8
                    BlendPixelRed = (WORD)((SrcPixelRed * 7/8)
                        + (RGB_R >> 3));
                    BlendPixelGreen = (WORD)((SrcPixelGreen * 7/8)
                        + (RGB_G >> 3));
                    BlendPixelBlue = (WORD)((SrcPixelBlue * 7/8)
                        + (RGB_B >> 3));
                    break;
                case 2://6/8
                    BlendPixelRed = (WORD)((SrcPixelRed * 2/3)
                        + RGB_R * 1/3);
                    BlendPixelGreen = (WORD)((SrcPixelGreen * 2/3)
                        + RGB_G * 1/3);
                    BlendPixelBlue = (WORD)((SrcPixelBlue * 2/3)
                        + RGB_B * 1/3);
                    break;
                case 3://5/8
                    BlendPixelRed = (WORD)((SrcPixelRed * 5/8)
                        + RGB_R * 3/8);
                    BlendPixelGreen = (WORD)((SrcPixelGreen * 5/8)
                        + RGB_G * 3/8);
                    BlendPixelBlue = (WORD)((SrcPixelBlue * 5/8)
                        + RGB_B * 3/8);
                    break;
                case 4://4/8
                    BlendPixelRed = (WORD)((SrcPixelRed >> 1)
                        + RGB_R  - (RGB_R >> 1));
                    BlendPixelGreen = (WORD)((SrcPixelGreen >> 1)
                        + RGB_G  - (RGB_G >> 1));
                    BlendPixelBlue = (WORD)((SrcPixelBlue >> 1)
                        + RGB_B  - (RGB_B >> 1));
                    break;
                case 5://3/8
                    BlendPixelRed = (WORD)(((SrcPixelRed >> 3) * 3)
                        + (RGB_R >> 3) * 5);
                    BlendPixelGreen = (WORD)(((SrcPixelGreen >> 3) * 3)
                        + (RGB_G >> 3) * 5);
                    BlendPixelBlue = (WORD)(((SrcPixelBlue >> 3) * 3)
                        + (RGB_B >> 3) * 5);
                    break;
                case 6://2/8
                    BlendPixelRed = (WORD)((SrcPixelRed >> 2)
                        + RGB_R  - (RGB_R >> 2));
                    BlendPixelGreen = (WORD)((SrcPixelGreen >> 2)
                        + RGB_G  - (RGB_G >> 2));
                    BlendPixelBlue = (WORD)((SrcPixelBlue >> 2)
                        + RGB_B  - (RGB_B >> 2));
                    break;
                case 7://1/8
                    // Improve efficiency
                default:
                    BlendPixelRed = (WORD)((SrcPixelRed >> 3)
                        + RGB_R  - (RGB_R >> 3));
                    BlendPixelGreen = (WORD)((SrcPixelGreen >> 3)
                        + RGB_G  - (RGB_G >> 3));
                    BlendPixelBlue = (WORD)((SrcPixelBlue >> 3)
                        + RGB_B  - (RGB_B >> 3));
                    break;
            }
            *pDesBuffer = ((BlendPixelRed & 0xF8) << 8) | ((BlendPixelGreen & 0xFC) << 3) | (BlendPixelBlue >> 3);

            pOverlay1Buffer++;
            pDesBuffer++;
        }
        pDesBuffer += (g_videoCtx.nMobileWidth - g_videoCtx.overlay1.Width);
    }
}

static void Overlay_Overlay1BufferCopy_RGB565()
{
    WORD *pDesBuffer;
    WORD *pOverlay1Buffer;

    pOverlay1Buffer = (WORD *)g_videoCtx.pOverlay1Fb;

    pDesBuffer = (WORD *)g_pSurface->pixels +
                    (g_videoCtx.nLCDPosY + g_videoCtx.overlay1.PosY) *
                    g_videoCtx.nMobileWidth + g_videoCtx.nLCDPosX +
                    g_videoCtx.overlay1.PosX;

    for (int i = 0; i < g_videoCtx.overlay1.Height; i++) {
        memcpy((Byte *)pDesBuffer, (Byte *)pOverlay1Buffer,
            g_videoCtx.overlay1.Width * 2);
        pOverlay1Buffer += g_videoCtx.overlay1.Width;
        pDesBuffer += (g_videoCtx.nMobileWidth - g_videoCtx.overlay1.Width);
    }
}

//When: 1. There has the overlap area(It's only mean three layer overlap)
//      2. There has transparence operation
//      3. Overlay2BufferCopy func has been completed
//      4. Overlay1BufferCopy func has not been done
//      5. Only support the baseplane RGBT555 now <--BUGBUG
static void Underlay_OverlapAreaOperation_Overlay1RGBT666()
{
    WORD *pDesBuffer;
    WORD *pBasePlaneBuffer;//RGBT555
    UInt32 *pOverlay1Buffer;
    pDesBuffer = (WORD *)g_pSurface->pixels +
                    (g_videoCtx.nLCDPosY + g_videoCtx.overlapArea.PosY) *
                    g_videoCtx.nMobileWidth + g_videoCtx.nLCDPosX +
                    g_videoCtx.overlapArea.PosX;

    pBasePlaneBuffer = (WORD *)g_videoCtx.pBasePlaneFb + g_videoCtx.overlapArea.PosX +
                    g_videoCtx.overlapArea.PosY * g_videoCtx.nLCDWidth;

    pOverlay1Buffer = (UInt32 *)g_videoCtx.pOverlay1Fb +
                    g_videoCtx.overlapArea.PosX - g_videoCtx.overlay1.PosX +
                    (g_videoCtx.overlapArea.PosY - g_videoCtx.overlay1.PosY) *
                    g_videoCtx.overlay1.Width;

    for(int j = 0; j < g_videoCtx.overlapArea.Height; j++) {
        for(int i = 0; i < g_videoCtx.overlapArea.Width; i++){
            if(*pBasePlaneBuffer >> 15){
                if(*pBasePlaneBuffer & 0x7FFF) {
                    if(((*pOverlay1Buffer >> 18) == 0) || (*pOverlay1Buffer & 0x3FFFF) != 0) {
                        *pDesBuffer = ColorRGBT555ToRGB565(*pBasePlaneBuffer);
                    }
                }//BUGBUG:If full trans, mix overlay1 and overlay2?
            }
            pDesBuffer++;
            pBasePlaneBuffer++;
            pOverlay1Buffer++;
        }
        pDesBuffer += (g_videoCtx.nMobileWidth - g_videoCtx.overlapArea.Width);
        pBasePlaneBuffer += (g_videoCtx.nLCDWidth - g_videoCtx.overlapArea.Width);
        pOverlay1Buffer += (g_videoCtx.overlay1.Width - g_videoCtx.overlapArea.Width);
    }
}

//When: 1. There has the overlap area(It's only mean three layer overlap)
//      2. There has transparence operation
//      3. Overlay2BufferCopy func has been completed
//      4. Overlay1BufferCopy func has not been done
//      5. Only support the baseplane RGBT555 now <--BUGBUG
static void Underlay_OverlapAreaOperation_Overlay1RGB565()
{
    WORD *pDesBuffer;
    WORD *pBasePlaneBuffer;//RGBT555
    WORD *pOverlay1Buffer;
    pDesBuffer = (WORD *)g_pSurface->pixels +
                    (g_videoCtx.nLCDPosY + g_videoCtx.overlapArea.PosY) *
                    g_videoCtx.nMobileWidth + g_videoCtx.nLCDPosX +
                    g_videoCtx.overlapArea.PosX;

    pBasePlaneBuffer = (WORD *)g_videoCtx.pBasePlaneFb + g_videoCtx.overlapArea.PosX +
                    g_videoCtx.overlapArea.PosY * g_videoCtx.nLCDWidth;

    pOverlay1Buffer = (WORD *)g_videoCtx.pOverlay1Fb +
                    g_videoCtx.overlapArea.PosX - g_videoCtx.overlay1.PosX +
                    (g_videoCtx.overlapArea.PosY - g_videoCtx.overlay1.PosY) *
                    g_videoCtx.overlay1.Width;

    for(int j = 0; j < g_videoCtx.overlapArea.Height; j++) {
        for(int i = 0; i < g_videoCtx.overlapArea.Width; i++){
            if(*pBasePlaneBuffer >> 15){
                if(*pBasePlaneBuffer & 0x7FFF) {
                    *pDesBuffer = ColorRGBT555ToRGB565(*pBasePlaneBuffer);
                }
            }
            pDesBuffer++;
            pBasePlaneBuffer++;
            pOverlay1Buffer++;
        }
        pDesBuffer += (g_videoCtx.nMobileWidth - g_videoCtx.overlapArea.Width);
        pBasePlaneBuffer += (g_videoCtx.nLCDWidth - g_videoCtx.overlapArea.Width);
        pOverlay1Buffer += (g_videoCtx.overlay1.Width - g_videoCtx.overlapArea.Width);
    }
}


static UInt32 SDLCALL DrawSurface(UInt32 interval)
{
    // If no render flag is set, and overlay is disable,
    // there's no need to update the surface.
    // Overlay is often used in video output in camera application
    // or media player, so automatically let the screen refresh.
    int static nCounter=0;
    nCounter++;
    if(nCounter==25)nCounter=0;//if grafix refresh,copy once per 40ms,or anyway,1s,for power management.
    else
    {
        if (!(g_videoCtx.bAutoRender || g_videoCtx.bRender
             || g_videoCtx.pOverlay2Fb)) return interval;
    }

    SDL_LockSurface(g_pSurface);
    g_videoCtx.bRender = FALSE;

    assert(NULL != g_videoCtx.pBaseplaneBufferCopy);
    g_videoCtx.pBaseplaneBufferCopy();

    if(g_videoCtx.bIsSetOverlay2) {
        assert(NULL != g_videoCtx.pOverlay2BufferCopy);
        g_videoCtx.pOverlay2BufferCopy();
    }

    if(g_videoCtx.bIsOverlap && g_videoCtx.bIsUnderlay) {
        assert(NULL != g_videoCtx.OverlapAreaOperation);
        g_videoCtx.OverlapAreaOperation();
    }

    if(g_videoCtx.bIsSetOverlay1) {
        assert(NULL != g_videoCtx.pOverlay1BufferCopy);
        g_videoCtx.pOverlay1BufferCopy();
    }

    SDL_UpdateRect(g_pSurface,
        g_videoCtx.nLCDPosX, g_videoCtx.nLCDPosY,
        g_videoCtx.nLCDWidth, g_videoCtx.nLCDHeight);

    SDL_UnlockSurface(g_pSurface);

    return interval;
}

static Boolean InitGlobalSurface(void * pArg)
{
    int flags = SDL_INIT_VIDEO | SDL_INIT_TIMER ;

    // SDL Initiation
    if (SDL_Init(flags) < 0) {
        return FALSE;
    }

    //SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);

    g_pSurface = SDL_SetVideoMode(g_videoCtx.nMobileWidth,
                            g_videoCtx.nMobileHeight,
                            SDLPIXELBITS,
                            SDL_HWSURFACE | SDL_DOUBLEBUF);
    if (g_pSurface == NULL) {
        printf("Failed to set video mode");
        //SDL_Quit();
        return FALSE;
    }

    // BuildMobileFace();
    // BuildMobileCursor();

    //SDL_WarpMouse(0, 0); // Default position of mouse
    SDL_UpdateRect(g_pSurface, 0, 0, 0, 0);
    return TRUE;
}

static int StartDrawSurface()
{

    SDL_TimerCallback callback = &DrawSurface;
    SDL_SetTimer(40, callback); // Update surface every 40 ms

    //SDL_WarpMouse(0, 0); // Default position of mouse

    g_videoCtx.bRender = TRUE;
    g_videoCtx.bAutoRender = FALSE;

    return 0;
}



void SetBasePlaneColorFormat(ColorFormat CFormat)
{
    if (COLOR_RGB565 == CFormat) {
        g_videoCtx.BasePlaneColorFormat = COLOR_RGB565;
        g_videoCtx.nBasePlanePixelBits = 16;
        g_videoCtx.nBasePlanePixelBytes = 2;
        g_videoCtx.nLCDColorBits = 16;
        g_videoCtx.pBaseplaneBufferCopy = BaseplaneBufferCopy_RGB565;
    }
    else if (COLOR_RGBT555 == CFormat) {
        g_videoCtx.BasePlaneColorFormat = COLOR_RGBT555;
        g_videoCtx.nBasePlanePixelBits = 16;
        g_videoCtx.nBasePlanePixelBytes = 2;
        g_videoCtx.nLCDColorBits = 16;
        g_videoCtx.pBaseplaneBufferCopy = BaseplaneBufferCopy_RGBT555;
    }
    else if (COLOR_RGBT666 == CFormat) {
        g_videoCtx.BasePlaneColorFormat = COLOR_RGBT666;
        g_videoCtx.nBasePlanePixelBits = 32;
        g_videoCtx.nBasePlanePixelBytes = 4;
        g_videoCtx.nLCDColorBits = 18;
        g_videoCtx.pBaseplaneBufferCopy = BaseplaneBufferCopy_RGBT666;
    }
    else {
        wprintf(L"This format isn't supported! Use RGB565 instead!\n");
        g_videoCtx.BasePlaneColorFormat = COLOR_RGB565;
        g_videoCtx.nBasePlanePixelBits = 16;
        g_videoCtx.nBasePlanePixelBytes = 2;
        g_videoCtx.nLCDColorBits = 16;
        g_videoCtx.pBaseplaneBufferCopy = BaseplaneBufferCopy_RGB565;
    }
}


void SetOverlay1ColorFormat(ColorFormat CFormat)
{
    if (COLOR_RGB565 == CFormat) {
        g_videoCtx.nOverlay1PixelBytes = 2;
        if(g_videoCtx.bIsUnderlay) {
            g_videoCtx.pOverlay1BufferCopy = Underlay_Overlay1BufferCopy_RGB565;
        } else {
            g_videoCtx.pOverlay1BufferCopy = Overlay_Overlay1BufferCopy_RGB565;
        }
    }
    else if (COLOR_RGBT666 == CFormat) {
        g_videoCtx.nOverlay1PixelBytes = 4;
        if(g_videoCtx.bIsUnderlay) {
            g_videoCtx.pOverlay1BufferCopy = Underlay_Overlay1BufferCopy_RGBT666;
        } else {
            g_videoCtx.pOverlay1BufferCopy = Overlay_Overlay1BufferCopy_RGBT666;
        }
    }
    else {
        g_videoCtx.nOverlay1PixelBytes = 4;
        if(g_videoCtx.bIsUnderlay) {
            g_videoCtx.pOverlay1BufferCopy = Underlay_Overlay1BufferCopy_RGBT666;
        } else {
            g_videoCtx.pOverlay1BufferCopy = Overlay_Overlay1BufferCopy_RGBT666;
        }
    }
}

static Boolean ConfigVideoMode()
{
    // BasePlaneColorFormat
    // Now only support RGB565 & RGBT666
    SetBasePlaneColorFormat(COLOR_RGB565);

    g_videoCtx.bIsOverlap = FALSE;
    g_videoCtx.bIsSetOverlay1 = FALSE;
    g_videoCtx.bIsSetOverlay2 = FALSE;


    g_VideoPowerMode=4;//if no power management,then keep hieghtest.
   // _SysCallNextHook(30,0,&g_BufferCopy);//else notify power manager

    // LCDWidth
    g_videoCtx.nLCDWidth = DEFAULT_LCDWIDTH;
    g_videoCtx.nLCDHeight = DEFAULT_LCDHEIGHT;
    g_videoCtx.bShowLCDOnly = FALSE;

    g_videoCtx.nMobileWidth = g_videoCtx.nLCDWidth;
    g_videoCtx.nMobileHeight = g_videoCtx.nLCDHeight;
    g_videoCtx.nLCDPosX = DEFAULT_LCDPOSX;
    g_videoCtx.nLCDPosY = DEFAULT_LCDPOSY;

    return TRUE;
}

static bool SetOverlayYCbCr422(OverlayFormat *pOverlayFormat){
    if (pOverlayFormat->Width > g_videoCtx.nMobileWidth
        || pOverlayFormat->Height > g_videoCtx.nMobileHeight)
        return FALSE;

    int nYCbCrOverlayBufSize;

    nYCbCrOverlayBufSize =
        2 * pOverlayFormat->Width * pOverlayFormat->Height;
    // YCbCrOverlayBufferSize should be 4 bytes aligned
    if (nYCbCrOverlayBufSize & 0x3) {
        nYCbCrOverlayBufSize = (nYCbCrOverlayBufSize + 0x3) & (~0x3);
    }

        g_videoCtx.pOverlay2Fb = realloc(g_videoCtx.pOverlay2Fb, nYCbCrOverlayBufSize);
    if (!g_videoCtx.pOverlay2Fb) return FALSE;
    memset(g_videoCtx.pOverlay2Fb, 0, nYCbCrOverlayBufSize);

    memcpy(&g_videoCtx.overlay2, pOverlayFormat, sizeof(OverlayFormat));

    // Y Channel
    g_videoCtx.overlay2.pChannelFb[0] = g_videoCtx.pOverlay2Fb;
    g_videoCtx.overlay2.ChannelSize[0] = nYCbCrOverlayBufSize / 2;

    // Cb Channel
    g_videoCtx.overlay2.pChannelFb[1] =
                        (Byte *)g_videoCtx.overlay2.pChannelFb[0] +
                        g_videoCtx.overlay2.ChannelSize[0];
    g_videoCtx.overlay2.ChannelSize[1] = nYCbCrOverlayBufSize / 4;

    // Cr Channel
    g_videoCtx.overlay2.pChannelFb[2] =
                        (Byte *)g_videoCtx.overlay2.pChannelFb[1] +
                        g_videoCtx.overlay2.ChannelSize[1];
    g_videoCtx.overlay2.ChannelSize[2] = nYCbCrOverlayBufSize / 4;

    if(g_videoCtx.bIsUnderlay) {
        g_videoCtx.pOverlay2BufferCopy = Underlay_Overlay2BufferCopy_YCbCr422;
    } else {
        g_videoCtx.pOverlay2BufferCopy = Overlay_Overlay2BufferCopy_YCbCr422;
    }

    return true;
}

static bool SetOverlayYCbCr420(OverlayFormat *pOverlayFormat){
    if (pOverlayFormat->Width > g_videoCtx.nMobileWidth
        || pOverlayFormat->Height > g_videoCtx.nMobileHeight)
        return FALSE;

    int nYCbCrOverlayBufSize;

    nYCbCrOverlayBufSize =
        pOverlayFormat->Width * pOverlayFormat->Height * 3 / 2;
    // YCbCrOverlayBufferSize should be 4 bytes aligned
    if (nYCbCrOverlayBufSize & 0x3) {
        nYCbCrOverlayBufSize = (nYCbCrOverlayBufSize + 0x3) & (~0x3);
    }

        g_videoCtx.pOverlay2Fb = realloc(g_videoCtx.pOverlay2Fb, nYCbCrOverlayBufSize);
    if (!g_videoCtx.pOverlay2Fb) return FALSE;
    memset(g_videoCtx.pOverlay2Fb, 0, nYCbCrOverlayBufSize);

    memcpy(&g_videoCtx.overlay2, pOverlayFormat, sizeof(OverlayFormat));

    // Y Channel
    g_videoCtx.overlay2.pChannelFb[0] = g_videoCtx.pOverlay2Fb;
    g_videoCtx.overlay2.ChannelSize[0] = nYCbCrOverlayBufSize *2 / 3;

    // Cb Channel
    g_videoCtx.overlay2.pChannelFb[1] =
                        (Byte *)g_videoCtx.overlay2.pChannelFb[0] +
                        g_videoCtx.overlay2.ChannelSize[0];
    g_videoCtx.overlay2.ChannelSize[1] = nYCbCrOverlayBufSize / 6;

    // Cr Channel
    g_videoCtx.overlay2.pChannelFb[2] =
                        (Byte *)g_videoCtx.overlay2.pChannelFb[1] +
                        g_videoCtx.overlay2.ChannelSize[1];
    g_videoCtx.overlay2.ChannelSize[2] = nYCbCrOverlayBufSize / 6;

    if(g_videoCtx.bIsUnderlay) {
        g_videoCtx.pOverlay2BufferCopy = Underlay_Overlay2BufferCopy_YCbCr420;
    } else {
        g_videoCtx.pOverlay2BufferCopy = Overlay_Overlay2BufferCopy_YCbCr420;
    }

    return true;
}
EXTERN_C void * Video_InitBasePlaneFramebuffer()
{
    static Boolean s_bBasePlaneInit = FALSE;

    if (s_bBasePlaneInit) {
        assert(g_videoCtx.pBasePlaneFb);
        return g_videoCtx.pBasePlaneFb;
    }
    s_bBasePlaneInit = TRUE;

    g_videoCtx.nBasePlaneSize = g_videoCtx.nLCDWidth
                              * g_videoCtx.nLCDHeight
                              * g_videoCtx.nBasePlanePixelBytes;

    g_videoCtx.pBasePlaneFb = (Byte *)VirtualAlloc(NULL,
        g_videoCtx.nBasePlaneSize * 2, MEM_RESERVE, PAGE_NOACCESS);
    if (NULL == g_videoCtx.pBasePlaneFb) {
        wprintf(L"Error: Can't allocate frame buffer.\n");
        return NULL;
    }

    // Reserved memory space, for avoiding to overwrite frame buffer
    g_videoCtx.pBasePlaneFb = (byte *)VirtualAlloc(
        g_videoCtx.pBasePlaneFb, g_videoCtx.nBasePlaneSize,
        MEM_COMMIT, PAGE_READWRITE);

    //clean screen
    memset(g_videoCtx.pBasePlaneFb, 0, g_videoCtx.nBasePlaneSize);

    //Set the tansparence array
    g_videoCtx.nTransArraySize = g_videoCtx.nLCDWidth * g_videoCtx.nLCDHeight;
    g_videoCtx.pTransArray = (Byte *)malloc(g_videoCtx.nTransArraySize);
    if (!g_videoCtx.pTransArray) return NULL;
    memset(g_videoCtx.pTransArray, 0, g_videoCtx.nTransArraySize);

    StartDrawSurface();

    printf("\t{LCD FrameBuff Map at %x, BufSize %x}\n",
        g_videoCtx.pBasePlaneFb, g_videoCtx.nBasePlaneSize);

    return g_videoCtx.pBasePlaneFb;
}

EXTERN_C Boolean Video_InitVideo()
{
    ConfigVideoMode();
    Boolean bSuccess = InitGlobalSurface(NULL);
    if (!bSuccess) {
        printf(" failed to init global grafix surface.\n");
    }
    return bSuccess;
}

EXTERN_C void Video_DisableOverlay(int layer);

EXTERN_C _ELASTOS Boolean Video_SetOverlay(OverlayFormat *pOverlayFormat)
{
    if (pOverlayFormat == NULL) return FALSE;

    if(pOverlayFormat->Width & 0x3) {
        pOverlayFormat->Width =
                (pOverlayFormat->Width + 0x3) & (~0x3);
    }

    g_videoCtx.bIsUnderlay = (pOverlayFormat->Flag == 0);

    if(g_videoCtx.bIsUnderlay &&
        (COLOR_RGB565 == g_videoCtx.BasePlaneColorFormat)) {
        SetBasePlaneColorFormat(COLOR_RGBT555);
    }

    if (pOverlayFormat->Enable) {
        if (pOverlayFormat->Layer == 2) {
            if (g_videoCtx.bIsSetOverlay2){
                g_videoCtx.bIsSetOverlay2 = FALSE;
                Sleep(DRAWSURFACETIMER);
            }
            switch(pOverlayFormat->Color) {
                case COLOR_YCbCr422:
                    if(!SetOverlayYCbCr422(pOverlayFormat)) goto ERR;
                    break;
                case COLOR_YCbCr420:
                    if(!SetOverlayYCbCr420(pOverlayFormat)) goto ERR;
                    break;
                default:
                    goto ERR;
            }
            g_videoCtx.bIsSetOverlay2 = TRUE;
        }
        if (1 == pOverlayFormat->Layer) {
            if (g_videoCtx.bIsSetOverlay1) {
                g_videoCtx.bIsSetOverlay1 = FALSE;
                Sleep(DRAWSURFACETIMER);
            }
            memcpy(&g_videoCtx.overlay1, pOverlayFormat, sizeof(OverlayFormat));
            SetOverlay1ColorFormat(g_videoCtx.overlay1.Color);

                g_videoCtx.pOverlay1Fb =
                    realloc(g_videoCtx.pOverlay2Fb, g_videoCtx.nOverlay1PixelBytes*g_videoCtx.overlay1.Width*g_videoCtx.overlay1.Height);
            if (!g_videoCtx.pOverlay1Fb) goto ERR;
            memset(g_videoCtx.pOverlay1Fb, 0,
                (g_videoCtx.nOverlay1PixelBytes*g_videoCtx.overlay1.Width*g_videoCtx.overlay1.Height));
            g_videoCtx.overlay1.pChannelFb[0] = g_videoCtx.pOverlay1Fb;
            g_videoCtx.overlay1.ChannelSize[0] =
                g_videoCtx.nOverlay1PixelBytes*g_videoCtx.overlay1.Width*g_videoCtx.overlay1.Height;
            g_videoCtx.bIsSetOverlay1 = TRUE;
        }
        if(g_videoCtx.bIsSetOverlay1 && g_videoCtx.bIsSetOverlay2) {
            g_videoCtx.bIsOverlap = GetTheoverlapArea();
            if(g_videoCtx.bIsUnderlay) {
                if(COLOR_RGB565 == g_videoCtx.overlay1.Color) {
                    g_videoCtx.OverlapAreaOperation = Underlay_OverlapAreaOperation_Overlay1RGB565;
                } else {
                    g_videoCtx.OverlapAreaOperation = Underlay_OverlapAreaOperation_Overlay1RGBT666;
                }
            }
        }
    }
    else {
        Video_DisableOverlay(pOverlayFormat->Layer);
    }

    printf("g_videoCtx.overlay2.pChannelFb[0]=%x\n",g_videoCtx.overlay2.pChannelFb[0]);

    return TRUE;

ERR:
    if(g_videoCtx.bIsUnderlay &&
        (COLOR_RGB565 == g_videoCtx.BasePlaneColorFormat)) {
        SetBasePlaneColorFormat(COLOR_RGB565);
    }

    return FALSE;

}

EXTERN_C void Video_DisableOverlay(Int32 layer)
{
    if ((layer&0x2)&&(g_videoCtx.pOverlay2Fb!=NULL )) {
        g_videoCtx.bIsSetOverlay2 = FALSE;
        Sleep(DRAWSURFACETIMER);
        free(g_videoCtx.pOverlay2Fb);
        g_videoCtx.pOverlay2Fb = NULL;
        g_videoCtx.pOverlay2BufferCopy = NULL;
    }

    if ((layer&0x1)&&(g_videoCtx.pOverlay1Fb!=NULL)) {
        g_videoCtx.bIsSetOverlay1 = FALSE;
        Sleep(DRAWSURFACETIMER);
        free(g_videoCtx.pOverlay1Fb);
        g_videoCtx.pOverlay1Fb = NULL;
        g_videoCtx.pOverlay1BufferCopy = NULL;
    }

    if((!g_videoCtx.bIsSetOverlay1) || (!g_videoCtx.bIsSetOverlay2)) {
        g_videoCtx.bIsOverlap = FALSE;
        g_videoCtx.OverlapAreaOperation = NULL;
    }

    if((!g_videoCtx.bIsSetOverlay1)&&(!g_videoCtx.bIsSetOverlay2)) {
        if((COLOR_RGBT555 == g_videoCtx.BasePlaneColorFormat)){
            SetBasePlaneColorFormat(COLOR_RGB565);
        }
    }

}

//inline  __int64 GetCycleCount()
//{
//__asm _emit 0x0F
//__asm _emit 0x31
//}

EXTERN_C void Video_Render()
{
    // bRender is a boolean flag to refresh the screen or not.
    // To improve efficiency, it isn't locked.
    // Actually, it needn't be locked.
    g_videoCtx.bRender = TRUE;
}

EXTERN_C void Video_AutoRender()
{
    g_videoCtx.bAutoRender = TRUE;
}

EXTERN_C void Video_SetTransLevel(Byte level)
{
    g_videoCtx.nTransparencyKey = level / 32; // [0, 255] -> [0, 7]
}


